package dev.ece.suit.defer;

import org.lwjgl.opengl.GL11;

import dev.ece.core.cells.decal.Decal;
import dev.ece.core.cells.decal.DecalShader;
import dev.ece.core.cells.model.AbstractModel;
import dev.ece.core.sprite.AbstractSprite;
import dev.ece.core.texture.FBOS;
import dev.ece.core.texture.Texture;
import dev.ece.core.vertex.VAO;
import dev.ece.core.vertex.VBO;
import dev.ece.util.lib.Vector3f;
import dev.ece.util.tools.Camera;

public class DecalComponent extends AbstractSprite implements Decal {

	private DecalShader shader;
	
	private Texture texture;
	
	private float decalSize = 1.0f;
	
	private DotBoxModel dotBoxModel;

	public DecalComponent(Texture texture) {
		this(DecalShader.getDefaultDecalShader(), texture);
	}
	
	public DecalComponent(Texture texture, float decalSize) {
		this(DecalShader.getDefaultDecalShader(), texture, decalSize);
	}
	
	public DecalComponent(DecalShader shader, Texture texture) {
		this(shader, texture, 1.0f);
	}
	
	public DecalComponent(DecalShader shader, Texture texture, float decalSize) {
		this.shader = shader;
		this.texture = texture;
		this.decalSize = decalSize;
		this.dotBoxModel = new DotBoxModel();
	}
	

	@Override
	public void onInitialize() {
		this.dotBoxModel.initialize();
	}

	@Override
	public void onRenderDeferredDecal(FBOS defer, Camera camera) {
		shader.glUseProgram();
		shader.glModelViewProjectMatrix();
		shader.glEceInvertModelViewMatrix();
		shader.glDecalSize(decalSize);
		shader.glTexture(texture);
		shader.glDefer(defer);
		dotBoxModel.render(camera, null);
	}

	public float getDecalSize() {
		return decalSize;
	}

	public void setDecalSize(float decalSize) {
		this.decalSize = decalSize;
	}

	@Override
	public synchronized void render(Camera camera) {}
	
	@Override
	public void destroy() {
		super.destroy();
		this.dotBoxModel.destroy();
		this.dotBoxModel = null;
	}

	@Override
	public void onLogic(Camera camera) {
		
	}

	@Override
	public void onRender(Camera camera) {
		
	}

	@Override
	public void clearup() {
		
	}

	@Override
	public boolean isNormalRender() {
		return false;
	}

	@Override
	public boolean isAlphaRender() {
		return false;
	}

}
class DotBoxModel extends AbstractModel<Integer> {

	private Vector3f[] vertice;

	private VBO verticeVBO;
	
	private VAO vao;
	
	public DotBoxModel() {
		this.setup();
	}
	
	public void setup() {
		vertice = createVertice();
		verticeVBO = VBO.newInstance(vertice);
	}
	
	protected Vector3f[] createVertice() {
		Vector3f[] vertice = new Vector3f[36];
		int index = 0;
		float length = 1;
		float x = length;
		float y = length;
		float z = length;
		//正面
		vertice[index ++] = new Vector3f(-x, y, z);
		vertice[index ++] = new Vector3f(-x, -y, z);
		vertice[index ++] = new Vector3f(x, y, z);
		vertice[index ++] = new Vector3f(x, y, z);
		vertice[index ++] = new Vector3f(-x, -y, z);
		vertice[index ++] = new Vector3f(x, -y, z);
		//后面
		vertice[index ++] = new Vector3f(x, y, -z);
		vertice[index ++] = new Vector3f(x, -y, -z);
		vertice[index ++] = new Vector3f(-x, y, -z);
		vertice[index ++] = new Vector3f(-x, y, -z);
		vertice[index ++] = new Vector3f(x, -y, -z);
		vertice[index ++] = new Vector3f(-x, -y, -z);
		//左
		vertice[index ++] = new Vector3f(-x, y, -z);
		vertice[index ++] = new Vector3f(-x, -y, -z);
		vertice[index ++] = new Vector3f(-x, y, z);
		vertice[index ++] = new Vector3f(-x, y, z);
		vertice[index ++] = new Vector3f(-x, -y, -z);
		vertice[index ++] = new Vector3f(-x, -y, z);
		//右
		vertice[index ++] = new Vector3f(x, y, z);
		vertice[index ++] = new Vector3f(x, -y, z);
		vertice[index ++] = new Vector3f(x, y, -z);
		vertice[index ++] = new Vector3f(x, y, -z);
		vertice[index ++] = new Vector3f(x, -y, z);
		vertice[index ++] = new Vector3f(x, -y, -z);
		//上
		vertice[index ++] = new Vector3f(x, y, z);
		vertice[index ++] = new Vector3f(x, y, -z);
		vertice[index ++] = new Vector3f(-x, y, z);
		vertice[index ++] = new Vector3f(-x, y, z);
		vertice[index ++] = new Vector3f(x, y, -z);
		vertice[index ++] = new Vector3f(-x, y, -z);
		//下
		vertice[index ++] = new Vector3f(x, -y, -z);
		vertice[index ++] = new Vector3f(x, -y, z);
		vertice[index ++] = new Vector3f(-x, -y, -z);
		vertice[index ++] = new Vector3f(-x, -y, -z);
		vertice[index ++] = new Vector3f(x, -y, z);
		vertice[index ++] = new Vector3f(-x, -y, z);
		return vertice;
	}
	
	@Override
	public void onInitialize() {
		vao = new VAO();
		vao.bind();
		vao.bindVertexArrayBuffer(verticeVBO, 3);
		vao.finish();
		
		verticeVBO = null;
	}

	@Override
	public void onRender(Camera camera, Integer value) {
		vao.bind();
		GL11.glDrawArrays(GL11.GL_TRIANGLES, 0, 36);
	}
	
	@Override
	public void onRenderAlpha(FBOS defer, Camera camera, Integer value) {}

	@Override
	public void onRenderDepthMap(Camera camera, Integer value) {}
	
	@Override
	public void destroy() {
		if(vao != null) {
			vao.destroy();
		}
		vao = null;
		vertice = null;
	}
	
}
